A programmable class can be an application server-side software component that encapsulates the business logic of an application. Objects (instances) of the class are created and managed at runtime as part of an application server to provide enterprise applications with a high level of abstraction. A major mechanism for the efficient reuse of objects is the caches and/or pools that are limited system memories capable of maintaining the objects at various stages of readiness for business use. Usually, a cache can maintain objects at a higher level of readiness than a pool can: although all objects can be pooled, only those objects in a cache can be enrolled in a transaction.
A cache maintains objects that are in two different states, “active” or “idle (inactive)”, distinguished by whether an object is currently enrolled in a transaction or not. An object is considered to be idle when it is not enrolled in a transaction, otherwise it is regarded as active. Objects that are involved in a transaction must be accessible via a cache. At any given time, any of these objects in the cache may hold uncommitted modifications, may be required to be available at commit time for data consistency checks, and may be waiting for future access and possible modification by an application. After a transaction commits, all the objects in the cache that were enrolled in the transaction remain in the cache but are eligible for replacement or re-enrollment in a new transaction.
The price for the gains in response time by the cache and pool is of course paid for by an increased usage of memory. A cache has a ceiling (limit) on its size (the number of objects it can maintain at any time). As the demands on the server providing business applications using objects can be periodic, the maximum allowed size of the cache must be large enough to satisfy the memory demands of peak system usage. A cache may start out empty at deployment time. As objects are enrolled in transactions to serve user requests, the cache grows monotonically to accommodate the increasing processing demands. While the cache may grow to meet increasing demands, it typically may not shrink in response to decreasing demand. Even in systems that are subject to cyclic demand, the memory taken by the cache is often not relinquished even if it is no longer needed after a period of peak demand. As a result, the idle objects that are kept in the cache during off-peak periods are needlessly holding on to the heap space they claimed to handle peak demand, causing an inefficient use of system memory resources. In addition, if the system workload increases to the point that when a newly enrolled object is to be added to the cache that is not large enough to hold all objects currently enrolled in transactions, a system failure may happen and whatever transaction that failed to add the object to the full cache would have to abort its work as a result.
Similarly, a pool starts off with a size equal to the value of the “initial-beans-in-free-pool” property of the pool specified in the configuration data of a class at deployment time. Over time, the size of the pool may grow up to a size that is limited by “max-beans-in-free-pool” property of the pool. As is the case for caches, the pool may automatically grow to meet increasing demands, but it often does not shrink automatically in response to decreasing demand. This is also an inefficient use of system memory resources.